﻿using System;
using System.ComponentModel;
using Castle.DynamicProxy;
using EntityAop.Configuration;
using EntityAop.Interceptors.InterfacesToImplement;
using EntityAop.Interceptors.Support;

namespace EntityAop.Interceptors
{
    public class InstanceSpecificInterceptor : BaseInterceptor
    {
        public InstanceSpecificInterceptor()
            : base()
        {
            MessageSendProcess = Configuration.ProxyGeneratorCreateFunc().Unproxy;

            RelatedTypes = new[] { typeof(INotifyPropertyChanged), typeof(INotifyOfPropertyChange) };
        }

        protected override void PerformProceed(IInvocation invocation)
        {
            var instanceSpecificData = InstanceSpecificHelper.GetInstanceSpecificData(invocation);

            var methodName = invocation.Method.Name;

            if (methodName == "add_PropertyChanged")
            {
                instanceSpecificData.PropertyChangedEventHandler = (PropertyChangedEventHandler)Delegate.Combine(instanceSpecificData.PropertyChangedEventHandler, (Delegate)invocation.Arguments[0]);

                return;
            }
            if (methodName == "remove_PropertyChanged")
            {
                instanceSpecificData.PropertyChangedEventHandler = (PropertyChangedEventHandler)Delegate.Remove(instanceSpecificData.PropertyChangedEventHandler, (Delegate)invocation.Arguments[0]);

                return;
            }

            if (methodName == "NotifyOfPropertyChange")
            {
                instanceSpecificData.PropertyChangedEventHandler(invocation.Proxy, new PropertyChangedEventArgs((string)invocation.Arguments[1]));

                return;
            }

            if (methodName == "RegisterInverseReference")
            {
                instanceSpecificData.RegisterInstanceToInverseReference((Type) invocation.Arguments[0], (int) invocation.Arguments[1]);

                return;
            }

            if (methodName == "UnRegisterInverseReference")
            {
                instanceSpecificData.UnregisterInstanceFromInverseReference((Type)invocation.Arguments[0], (int)invocation.Arguments[1]);

                return;
            }

            base.PerformProceed(invocation);

            if (!Configuration.IsInProxyCreationPhase)
            {
                NotificationHelper.NotifyDependent(invocation, methodName, instanceSpecificData.PropertyChangedEventHandler);
            }

            if (!Configuration.IsInProxyCreationPhase)
            {
                if (invocation.ReturnValue == invocation.InvocationTarget)
                {
                    invocation.ReturnValue = invocation.Proxy;
                }
            }
        }
    }
}
